#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <EEPROM.h>
#include <FastLED.h>

// WiFi 和 LED 配置
#define LED_PIN 13
#define NUM_LEDS 3
CRGB leds[NUM_LEDS];

const char* apSSID = "ESP12F";         //热点名称
const char* apPassword = "123654789";  //热点密码

// 引脚配置
const int controlPin = 4;
const int detectPin = 5;
const int buttonPin = 12;

// 状态变量
bool isComputerOn = false;
bool ledEnabled = true;  // 初始状态为打开
bool apMode = false;

// LED 亮度变量
#define DEFAULT_BRIGHTNESS 5  // 亮度范围 0-255
int ledBrightness = DEFAULT_BRIGHTNESS;

// WiFi 配置
AsyncWebServer server(80);
struct WiFiConfig {
  char ssid[32];
  char password[64];
};
const int MAX_WIFI_CONFIGS = 10;
WiFiConfig wifiConfigs[MAX_WIFI_CONFIGS];
int storedConfigs = 0;

// 定时变量
unsigned long previousMillis = 0;
const long interval = 10000;  // 10秒，重试间隔
unsigned long lastReconnectAttempt = 0;
bool isConnectingWiFi = false;

// 验证参数 m
String correctM = "123654789.";  // 修改此变量以改变参数 m 的值

// 长按和短按控制变量
bool pressActive = false;
unsigned long pressStart = 0;
unsigned long pressDuration = 0;

// 在全局变量部分添加自定义的 IP 地址、子网掩码和网关地址
IPAddress apIP(192, 168, 10, 1);  // 自定义热点 IP 地址
IPAddress netMask(255, 255, 255, 0);  // 子网掩码
IPAddress gateway(192, 168, 10, 1);  // 自定义网关地址

void loadWiFiConfigs() {
  EEPROM.begin(4096);
  EEPROM.get(0, wifiConfigs);
  EEPROM.get(sizeof(wifiConfigs), storedConfigs);
  EEPROM.end();
  if (storedConfigs > MAX_WIFI_CONFIGS || storedConfigs < 0) {
    storedConfigs = 0;
  }
}

void saveWiFiConfigs() {
  EEPROM.begin(4096);
  EEPROM.put(0, wifiConfigs);
  EEPROM.put(sizeof(wifiConfigs), storedConfigs);
  EEPROM.commit();
  EEPROM.end();
}

void connectToWiFi() {
  if (apMode || isConnectingWiFi) {
    return;
  }
  if (millis() - lastReconnectAttempt < interval) {
    return;
  }
  Serial.println("尝试连接 WiFi: ");
  isConnectingWiFi = true;  // 开始连接，设置标志位
  WiFi.disconnect();
  WiFi.hostname("ESP12F");  // 设置Wi-Fi客户端名称为ESP12F

  bool allFailed = true;
  for (int i = 0; i < storedConfigs; i++) {
    WiFi.begin(wifiConfigs[i].ssid, wifiConfigs[i].password);
    unsigned long startTime = millis();
    while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {  // 10秒超时重试连接
      delay(500);
      Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
      leds[0] = CRGB::Green;
      FastLED.show();
      startAllServices();  // 连接Wi-Fi后启动所有服务
      Serial.println("\n连接到 WiFi: " + String(wifiConfigs[i].ssid));
      Serial.print("IP 地址: ");
      Serial.println(WiFi.localIP());
      lastReconnectAttempt = 0;
      allFailed = false;
      break;
    }
  }

  if (allFailed) {
    leds[0] = CRGB::Red;
    FastLED.show();
    Serial.println("\n未能连接到任何存储的 WiFi。");
    lastReconnectAttempt = millis();
  }
  isConnectingWiFi = false;  // 连接结束，清除标志位
}

void startAPMode() {
  apMode = true;
  // 配置热点的 IP 地址、子网掩码和网关地址
  WiFi.softAPConfig(apIP, gateway, netMask);
  WiFi.softAP(apSSID, apPassword);
  startAllServices();  // AP 模式下也启动所有服务
  Serial.println("开启 AP 模式");
  Serial.print("AP IP 地址: ");
  Serial.println(WiFi.softAPIP());
}

bool validateM(AsyncWebServerRequest* request) {
  if (request->hasParam("m")) {
    String m = request->getParam("m")->value();
    if (m == correctM) {
      return true;
    } else {
      request->send(400, "text/plain; charset=utf-8", "无效的 验证 参数");
      return false;
    }
  } else {
    request->send(400, "text/plain; charset=utf-8", "缺少 验证 参数");
    return false;
  }
}

void startAllServices() {
  server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
    String html = R"rawliteral(
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>ESP12F 验证页面</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                text-align: center;
                margin: 0;
                padding: 20px;
                background-color: #f4f4f4;
            }
            * {
                box-sizing: border-box;
            }
            h1 {
                color: #333;
            }
            input, button {
                padding: 10px;
                margin: 10px 0;
                border: none;
                border-radius: 5px;
                font-size: 16px;
                cursor: pointer;
            }
            button {
                background-color: #007BFF;
                color: white;
            }
            button:hover {
                background-color: #0056b3;
            }
        </style>
        <script>
            function validateAndRedirect() {
                var mValue = document.getElementById('mInput').value;
                if (mValue!== '') {
                    window.location.href = '/config?m=' + mValue;
                } else {
                    alert('请输入 m 值');
                }
            }
        </script>
    </head>
    <body>
        <h1>ESP12F 验证页面</h1>
        <input type="text" id="mInput" placeholder="输入 m 值">
        <button onclick="validateAndRedirect()">确定</button>
    </body>
    </html>
    )rawliteral";
    request->send(200, "text/html; charset=utf-8", html);
  });

  // 渲染配置页面
  server.on("/config", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      String html = R"rawliteral(
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>ESP12F 配置页面</title>
            <style>
                body {
                    font-family: Arial, sans-serif;
                    text-align: center;
                    margin: 0;
                    padding: 20px;
                    background-color: #f4f4f4;
                }
                * {
                    box-sizing: border-box;
                }
                h1 {
                    color: #333;
                }
                .container {
                    max-width: 400px;
                    margin: 0 auto;
                    background: #fff;
                    padding: 20px;
                    border-radius: 10px;
                    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
                }
                button, input {
                    width: 100%;
                    padding: 15px;
                    margin: 10px 0;
                    border: none;
                    border-radius: 5px;
                    font-size: 18px;
                    cursor: pointer;
                }
                button {
                    background-color: #007BFF;
                    color: white;
                }
                button:hover {
                    background-color: #0056b3;
                }
                .response {
                    margin-top: 10px;
                    padding: 10px;
                    border: 1px solid #000;
                    background: #e9ecef;
                    text-align: left;
                    font-size: 14px;
                    border-radius: 5px;
                    display: none;
                }
                .btn-red{
                    background-color: #ff007d;
                }
            </style>
            <script>
                function sendRequest(url, responseId) {
                    let separator = url.includes('?') ? '&' : '?';
                    var xhr = new XMLHttpRequest();
                    xhr.open('GET', url + separator + 'm=)rawliteral"
                    + String(correctM) + R"rawliteral(', true);
                    xhr.onload = function() {
                        var responseElement = document.getElementById(responseId);
                        responseElement.style.display = 'block';
                        let now = new Date();
                        let formattedTime = now.getFullYear() + '-' + 
                                ('0' + (now.getMonth() + 1)).slice(-2) + '-' + 
                                ('0' + now.getDate()).slice(-2) + ' ' + 
                                ('0' + now.getHours()).slice(-2) + ':' + 
                                ('0' + now.getMinutes()).slice(-2) + ':' + 
                                ('0' + now.getSeconds()).slice(-2);
                        if (xhr.status == 200) {
                            responseElement.innerHTML = '<strong>' + url + ' ' + formattedTime + '</strong>: ' + xhr.responseText + '<br>';
                        } else {
                            responseElement.innerHTML = '<strong>' + url + ' ' + formattedTime + '</strong>: 请求失败 (' + xhr.status + ')' + '<br>';
                        }
                    };
                    xhr.send();
                }

                function sendRequestWithParam(url, responseId) {
                    var param = '';
                    if (url === '/setbrightness') {
                        param = 'value=' + document.getElementById('brightness').value;
                    }
                    if (url === '/setwifi') {
                        param = 'n=' + document.getElementById('ssid').value + '&p=' + document.getElementById('password').value;
                    }
                    sendRequest(url + '?' + param, responseId);
                }
            </script>
        </head>
        <body>
            <h1>ESP12F 配置页面</h1>
            <div class="container">
                <button onclick='sendRequest("/power", "response-power")'>开机</button>
                <div id="response-power" class="response"></div>

                <button onclick='sendRequest("/mpower", "response-mpower")'>强制开机</button>
                <div id="response-mpower" class="response"></div>

                <button onclick='sendRequest("/mmpower", "response-mmpower")'>长按开机</button>
                <div id="response-mmpower" class="response"></div>

                <button onclick='sendRequest("/ledoff", "response-ledoff")'>关闭 LED</button>
                <div id="response-ledoff" class="response"></div>

                <button onclick='sendRequest("/ledon", "response-ledon")'>打开 LED</button>
                <div id="response-ledon" class="response"></div>

                <input type='number' id='brightness' min='0' max='255' value=')rawliteral"
                    + String(ledBrightness) + R"rawliteral('>
                <button onclick='sendRequestWithParam("/setbrightness", "response-brightness")'>设置亮度</button>
                <div id="response-brightness" class="response"></div>

                <input type='text' id='ssid' placeholder='输入SSID'>
                <input type='password' id='password' placeholder='输入密码'>
                <button onclick='sendRequestWithParam("/setwifi", "response-wifi")'>设置 WiFi</button>
                <div id="response-wifi" class="response"></div>

                <button class='btn-red' onclick='sendRequest("/clean", "response-clean")'>清除 WiFi 配置</button>
                <div id="response-clean" class="response"></div>

                <button onclick='sendRequest("/init", "response-init")'>重新连接 WiFi</button>
                <div id="response-init" class="response"></div>

                <button onclick='sendRequest("/showwifis", "response-showwifis")'>显示存储的 WiFi 配置</button>
                <div id="response-showwifis" class="response"></div>

                <button onclick='sendRequest("/status", "response-status")'>获取电脑状态</button>
                <div id="response-status" class="response"></div>
            </div>
        </body>
        </html>
        )rawliteral";
      request->send(200, "text/html; charset=utf-8", html);
    }
  });

  // 无论在AP模式下还是Wi-Fi连接模式下，都开启所有需要的服务
  server.on("/status", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      String status = isComputerOn ? "电脑已开机" : "电脑已关机";
      request->send(200, "text/plain; charset=utf-8", status);
    }
  });

  server.on("/power", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      if (isComputerOn) {
        request->send(200, "text/plain; charset=utf-8", "电脑已经是开机状态");
      } else {
        // 执行开机命令
        // 模拟按下电源键
        pressActive = true;
        pressStart = millis();
        pressDuration = 500;  // 设置短按时间
        request->send(200, "text/plain; charset=utf-8", "已执行短按开机键动作");
      }
    }
  });

  server.on("/mpower", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      // 不检测电脑状态，直接执行开机动作
      pressActive = true;
      pressStart = millis();
      pressDuration = 500;  // 设置短按时间
      request->send(200, "text/plain; charset=utf-8", "已执行强制短按开机键动作");
    }
  });

  server.on("/mmpower", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      // 不检测电脑状态，直接执行开机动作
      // 开始长按开机键动作
      pressActive = true;
      pressStart = millis();
      pressDuration = 5000;  // 设置长按时间
      request->send(200, "text/plain; charset=utf-8", "已执行长按开机键动作");
    }
  });

  server.on("/setwifi", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      if (request->hasParam("n") && request->hasParam("p")) {
        String ssid = request->getParam("n")->value();
        String password = request->getParam("p")->value();
        bool updated = false;
        for (int i = 0; i < storedConfigs; i++) {
          if (ssid == wifiConfigs[i].ssid) {
            strncpy(wifiConfigs[i].password, password.c_str(), sizeof(wifiConfigs[i].password));
            updated = true;
            break;
          }
        }
        if (!updated && storedConfigs < MAX_WIFI_CONFIGS) {
          strncpy(wifiConfigs[storedConfigs].ssid, ssid.c_str(), sizeof(wifiConfigs[storedConfigs].ssid));
          strncpy(wifiConfigs[storedConfigs].password, password.c_str(), sizeof(wifiConfigs[storedConfigs].password));
          storedConfigs++;
        }
        saveWiFiConfigs();
        request->send(200, "text/plain; charset=utf-8", "WiFi 配置已保存");
      } else {
        request->send(400, "text/plain; charset=utf-8", "缺少参数");
      }
    }
  });

  server.on("/clean", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      storedConfigs = 0;
      saveWiFiConfigs();
      request->send(200, "text/plain; charset=utf-8", "所有 WiFi 配置已清除");
    }
  });

  server.on("/init", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      apMode = false;
      WiFi.softAPdisconnect(true);
      connectToWiFi();
      request->send(200, "text/plain; charset=utf-8", "重新连接 WiFi 中");
    }
  });

  server.on("/ledoff", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      turnOffAllLEDs();
      ledEnabled = false;  // 设置状态为关闭
      request->send(200, "text/plain; charset=utf-8", "LED 灯已关闭");
    }
  });

  server.on("/ledon", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      if (ledEnabled) {
        FastLED.setBrightness(ledBrightness);  // 设置亮度
        FastLED.show();
      }
      ledEnabled = true;  // 设置状态为打开
      request->send(200, "text/plain; charset=utf-8", "LED 灯已打开");
    }
  });

  // 通过 web 请求调整亮度
  server.on("/setbrightness", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      if (request->hasParam("value")) {
        int value = request->getParam("value")->value().toInt();
        if (value >= 0 && value <= 255) {
          ledBrightness = value;
          if (ledEnabled) {
            FastLED.setBrightness(ledBrightness);  // 只有在LED开启的情况下才调整亮度
            FastLED.show();
          }
          request->send(200, "text/plain; charset=utf-8", "亮度已更新至 " + String(ledBrightness));
        } else {
          request->send(400, "text/plain; charset=utf-8", "无效的亮度值 (0-255)");
        }
      } else {
        request->send(400, "text/plain; charset=utf-8", "缺少亮度参数");
      }
    }
  });

  // 显示已存储的 WiFi 配置
  server.on("/showwifis", HTTP_GET, [](AsyncWebServerRequest* request) {
    if (validateM(request)) {
      String html = "<!DOCTYPE html><html><head><title>存储的 WiFi 配置</title></head><body>";
      html += "<h1>存储的 WiFi 配置</h1><ul>";
      for (int i = 0; i < storedConfigs; i++) {
        html += "<li>SSID: " + String(wifiConfigs[i].ssid) + " 密码: " + String(wifiConfigs[i].password) + "</li>";
      }
      html += "</ul></body></html>";
      request->send(200, "text/html;charset=utf-8", html);
    }
  });

  server.begin();
}

// 关闭所有 LED 的函数
void turnOffAllLEDs() {
  FastLED.clear();
  FastLED.show();
}

void updateLEDs() {
  // 如果LED未开启，清空显示并返回
  if (!ledEnabled) {
    turnOffAllLEDs();
    return;
  }

  // 设置全局亮度
  FastLED.setBrightness(ledBrightness);

  // 设置第一个LED的颜色，根据WiFi连接状态
  if (WiFi.status() == WL_CONNECTED) {
    leds[0] = CRGB::Green;
  } else {
    leds[0] = CRGB::Red;
  }

  // 设置第二个LED的颜色，根据电脑开机状态
  leds[1] = isComputerOn ? CRGB::Green : CRGB::Red;

  // 设置第三个LED的颜色，使其亮度变化更慢
  static float brightness = 0.0;
  static int direction = 1;
  static unsigned long lastUpdate = 0;
  unsigned long currentMillis = millis();

  // 每50ms更新一次亮度
  if (currentMillis - lastUpdate >= 50) {
    lastUpdate = currentMillis;
    if (WiFi.status() == WL_CONNECTED && isComputerOn) {
      brightness += direction * 0.005;  // 减小亮度变化步长

      if (brightness >= 1.0 || brightness <= 0.0) {
        direction *= -1;
      }

      leds[2] = CHSV(millis() / 15 % 255, 255, brightness * 255);  // 减慢颜色变化速度
    } else {
      leds[2] = CRGB::Black;
    }
  }

  FastLED.show();
}


void setup() {
  Serial.begin(115200);

  // 初始化引脚模式
  pinMode(controlPin, OUTPUT);
  pinMode(detectPin, INPUT_PULLUP);
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(controlPin, HIGH);  // 初始状态为关闭（高电平）

  // 初始化 LED
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();

  // 加载 WiFi 配置并尝试连接
  loadWiFiConfigs();
  connectToWiFi();
}

void loop() {
  // 检测电脑是否开机
  isComputerOn = digitalRead(detectPin) == LOW;

  // 检测按键是否被按下，如果按下则启动 AP 模式
  if (digitalRead(buttonPin) == LOW && !apMode) {
    startAPMode();
  }

  // 如果 WiFi 断开连接且不在 AP 模式下则重连
  if (WiFi.status() != WL_CONNECTED && !apMode) {
    connectToWiFi();
  }

  // 检测开机键动作
  if (pressActive) {
    if (millis() - pressStart >= pressDuration) {
      digitalWrite(controlPin, HIGH);
      pressActive = false;
    } else {
      digitalWrite(controlPin, LOW);
    }
  }

  // 更新 LED 状态
  updateLEDs();
}